﻿/*******************************************************
* Copyright (c) 2018-2088, By XuXiang all rights reserved.
*
* FileName: FightModule.cpp
* Summary: 战斗模块。
*
* Author: XuXiang
* Date: 2024-05-20 22:42
*******************************************************/

#include "FightModule.h"
#include "FightDefine.h"
#include "../../Game/ServerGame.h"
#include "../Login/LoginDefine.h"
#include "../Login/LoginModule.h"
#include "../Match/MatchDefine.h"
#include <algorithm>
#include <sstream>
#include <assert.h>
#include <Frame/MainBase.h>
#include <Frame/ServerBase.h>
#include <Frame/NetManagerBase.h>
#include <Frame/EventManager.h>
#include <Protocol/NetMsgFight.h>
#include <Util/StringUtil.h>
#include <Util/TimeUtil.h>

namespace Competition
{
	int FightModule::SelectRoleTime = 60;

	int FightModule::FightWatiTime = 5;

	FightModule::FightModule() : m_CurGroupID(1)
	{
	}

	FightModule::~FightModule()
	{
		SAFE_DELETE_MAP(m_FightGroups);
	}

	void FightModule::RegisterNetMessage(NetManagerBase *pMgr)
	{
		NET_REGISTER(pMgr, MsgID::CS_FIGHT_STATE, OnFightStateRequest);
		NET_REGISTER(pMgr, MsgID::CS_FIGHT_SELECT_ROLE, OnFightSelectRoleRequest);
		NET_REGISTER(pMgr, MsgID::CS_FIGHT_LOADING_PROGRESS, OnFightLoadingProgressRequest);
		NET_REGISTER(pMgr, MsgID::CS_FIGHT_OPERATE, OnFightOperateRequest);
		NET_REGISTER(pMgr, MsgID::CS_FIGHT_RESULT, OnFightResultRequest); 
		NET_REGISTER(pMgr, MsgID::CS_FIGHT_QUIT, OnFightQuitRequest);
		NET_REGISTER(pMgr, MsgID::CS_FIGHT_FRAME_RECORD, OnFightFrameRecordRequest);

		EventManager* emgr = EventManager::GetInstance();
		emgr->RegisterCallBack(MatchEvent::EID_MATCH_COMPLETE, OnEventMatchComplete, this);
		emgr->RegisterCallBack(LoginEvent::EID_USER_OUTLINE, OnEventUserOutline, this);
	}

	void FightModule::RegisterStorageMessage(StorageManager* pMgr)
	{

	}

	void FightModule::AddConfig(vector<ModuleConfig*> &cfgs)
	{
	}

	void FightModule::Init()
	{
		ModuleBase::Init();
	}

	void FightModule::OnUpdate()
	{
		Int64 ft = TimeUtil::GetCurrentMillisecond() - 5000;
		for (FightGroupMap::iterator itr = m_FightGroups.begin(); itr != m_FightGroups.end(); ++itr)
		{
			FightGroupInfo* group = itr->second;
			if (group->GetState() == FightGroupState::FGS_FIGHTING && group->GetStartTime() < ft)
			{
				SCFightOperateFrameNotify ntf;
				group->UpdateFightFrame(ntf);
				FightPlayerInfoVector& players = group->GetPlayerInfos();
				for (FightPlayerInfoVector::iterator itr2 = players.begin(); itr2 != players.end(); itr2++)
				{
					SendNet((*itr2)->GetUserID(), MsgID::SC_FIGHT_OPERATE_FRAME, &ntf);
				}
			}
		}
	}

	void FightModule::Release()
	{
		ModuleBase::Release();
	}

	void FightModule::OnUpdatePerSecond()
	{
		
	}

	FightGroupInfo* FightModule::GetUserGroup(int user_id)
	{
		auto itr = m_UserToGroup.find(user_id);
		if (itr == m_UserToGroup.end())
		{
			return NULL;
		}

		auto itr2 = m_FightGroups.find(itr->second);
		if (itr2 == m_FightGroups.end())
		{
			return NULL;
		}
		return itr2->second;
	}

	//判断用户是否在战斗中
	int FightModule::GetPlayerFightState(int user_id)
	{
		auto group = GetUserGroup(user_id);
		if (group == NULL)
		{
			return false;
		}
		auto player = group->GetPlayer(user_id);
		if (player == NULL)
		{
			return false;
		}
		return player->GetState();
	}

	void FightModule::OnFightStateRequest(NetDataItem* item)
	{
		int user_id = (int)item->key.second;
		CSFightStateRequest req;
		req.Unpack(item->data, 0);
		::printf("FightModule::OnFightStateRequest user_id:%d\n", user_id);

		//const Int32 SC_FIGHT_STATE = 3401;					//战斗状态通知
		SCFightStateResponse res;
		FightGroupInfo* ginfo = GetUserGroup(user_id);
		if (ginfo == NULL)
		{
			res.State = 0;
			SendNet(user_id, MsgID::SC_FIGHT_STATE, &res);
			return;
		}

		//如果时掉线状态则切换到正常状态，并发送进入事件
		auto player = ginfo->GetPlayer(user_id);
		if (player->GetState() == FightPlayerState::FPS_OUTLINE)
		{
			player->SetState(FightPlayerState::FPS_NORMAL);
			EventParam* ep = EventParam::Get(FightEvent::EID_FIGHT_IN);
			ep->i1 = user_id;
			EventManager::GetInstance()->TriggerEvent(ep);
		}
		else if (player->GetState() == FightPlayerState::FPS_QUIT)
		{
			res.State = 4;
			SendNet(user_id, MsgID::SC_FIGHT_STATE, &res);
			return;
		}

		//回复其它状态数据
		LoginModule* login_module = GetServer()->GetModule<LoginModule>();
		FightPlayerInfoVector& players = ginfo->GetPlayerInfos();
		res.State = (Byte)ginfo->GetState();
		res.PlayerCount = (int)players.size();
		for (int i = 0; i < res.PlayerCount; ++i)
		{
			auto fp = players[i];
			Competition::Net::FightPlayerInfo nfp;

			nfp.UserID = fp->GetUserID();
			nfp.NickName = login_module->GetUser(fp->GetUserID())->GetNickName();
			nfp.RoleID = (SByte)fp->GetRoleID();
			nfp.RoleConfigID = fp->GetRoleConfigID();
			nfp.Confirm = (Byte)(fp->IsConfirm() ? 1 : 0);
			res.PlayerList.push_back(nfp);
		}
		if (ginfo->GetState() == FightGroupState::FGS_SELECT_ROLE)
		{
			res.Param = SelectRoleTime - (int)(TimeUtil::GetCurrentMillisecond() - ginfo->GetStartTime()) / 1000;
		}
		else if (ginfo->GetState() == FightGroupState::FGS_FIGHTING)
		{
			res.Param = ginfo->GetFrameIndex();
			res.RandSeed = ginfo->GetRandSeed();
		}
		SendNet(user_id, MsgID::SC_FIGHT_STATE, &res);
	}

	void FightModule::OnFightSelectRoleRequest(NetDataItem* item)
	{
		int user_id = (int)item->key.second;
		CSFightSelectRoleRequest req;
		req.Unpack(item->data, 0);
		::printf("FightModule::OnFightSelectRoleRequest user_id:%d\n", user_id);

		//修改玩家角色
		FightGroupInfo* ginfo = GetUserGroup(user_id);
		if (ginfo == NULL)
		{
			return;
		}
		auto player = ginfo->GetPlayer(user_id);
		assert(player != NULL);
		player->SetRoleConfigID(req.RoleConfigID);
		player->SetConfirm(req.Confirm != 0);

		//const Int32 SC_FIGHT_SELECT_ROLE = 3402;			//选择角色通知
		SCFightSelectRoleNotify ntf;
		ntf.UserID = user_id;
		ntf.RoleConfigID = player->GetRoleConfigID();
		ntf.Confirm = player->IsConfirm() ? 1 : 0;
		FightPlayerInfoVector& players = ginfo->GetPlayerInfos();
		bool all_cnofirm = true;
		for (FightPlayerInfoVector::iterator itr = players.begin(); itr != players.end(); itr++)
		{
			all_cnofirm = all_cnofirm && (*itr)->IsConfirm();
			SendNet((*itr)->GetUserID(), MsgID::SC_FIGHT_SELECT_ROLE, &ntf);
		}

		//const Int32 SC_FIGHT_SELECT_ROLE_END = 3403;		//选择角色结束通知
		if (all_cnofirm)
		{
			SCFightSelectRoleEndNotify ntf2;
			ginfo->SetState(FightGroupState::FGS_LOADING);
			for (FightPlayerInfoVector::iterator itr = players.begin(); itr != players.end(); itr++)
			{
				SendNet((*itr)->GetUserID(), MsgID::SC_FIGHT_SELECT_ROLE_END, &ntf2);
			}
		}
	}

	void FightModule::OnFightLoadingProgressRequest(NetDataItem* item)
	{
		int user_id = (int)item->key.second;
		CSFightLoadingProgressRequest req;
		req.Unpack(item->data, 0);

		//修改玩家角色
		FightGroupInfo* ginfo = GetUserGroup(user_id);
		if (ginfo == NULL)
		{
			return;
		}
		auto player = ginfo->GetPlayer(user_id);
		assert(player != NULL);
		player->SetLoadProgress(req.Progress);
		player->SetLoadOK(req.Completed != 0);

		//const Int32 SC_FIGHT_LOADING_PROGRESS = 3404;		//加载进度通知
		SCFightLoadingProgressNotify ntf;
		ntf.UserID = user_id;
		ntf.Progress = player->GetLoadProgress();
		ntf.Completed = player->IsLoadOK() ? 1 : 0;
		FightPlayerInfoVector& players = ginfo->GetPlayerInfos();
		bool all_ok = true;
		for (FightPlayerInfoVector::iterator itr = players.begin(); itr != players.end(); itr++)
		{
			all_ok = all_ok && (*itr)->IsLoadOK();
			SendNet((*itr)->GetUserID(), MsgID::SC_FIGHT_LOADING_PROGRESS, &ntf);
		}

		//const Int32 SC_FIGHT_BEGIN = 3405;				//战斗开始通知
		if (all_ok)
		{
			ginfo->SetState(FightGroupState::FGS_FIGHTING);
			ginfo->SetStartTime(TimeUtil::GetCurrentMillisecond());
			ginfo->SetRandSeed(rand());

			SCFightBeginNotify ntf2;
			ntf2.RandSeed = ginfo->GetRandSeed();
			ntf2.StartTime = ginfo->GetStartTime();
			ntf2.LastTime = FightWatiTime;
			for (FightPlayerInfoVector::iterator itr = players.begin(); itr != players.end(); itr++)
			{
				SendNet((*itr)->GetUserID(), MsgID::SC_FIGHT_BEGIN, &ntf2);
			}
		}
	}

	void FightModule::OnFightOperateRequest(NetDataItem* item)
	{
		int user_id = (int)item->key.second;
		CSFightOperateRequest req;
		req.Unpack(item->data, 0);

		//必须是战斗中的玩家信息
		auto group = GetUserGroup(user_id);
		if (group == NULL || group->GetState() != FightGroupState::FGS_FIGHTING)
		{
			return;
		}
		auto player = group->GetPlayer(user_id);
		if (player == NULL)
		{
			return;
		}

		int index = 0;
		int op = DataUtil::ReadByte(req.Bytes, index, &index);
		Int16 move_p1 = 0;
		Int16 move_p2 = 0;
		int skill_id = 0;
		int skill_p1 = 0;
		int skill_p2 = 0;
		switch (op)
		{
		case OperateType::OPT_MOVE:
			move_p1 = DataUtil::ReadInt16(req.Bytes, index, &index);
			move_p2 = DataUtil::ReadInt16(req.Bytes, index, &index);
			player->DoMove(move_p1, move_p2);
			break;
		case OperateType::OPT_CAST_SKILL:
			skill_id = DataUtil::ReadInt32(req.Bytes, index, &index);
			skill_p1 = DataUtil::ReadInt32(req.Bytes, index, &index);
			skill_p2 = DataUtil::ReadInt32(req.Bytes, index, &index);
			player->DoSkillCast(skill_id, skill_p1, skill_p2);
			break;
		case OperateType::OPT_SKILL_PRESS:
			skill_id = DataUtil::ReadInt32(req.Bytes, index, &index);
			player->DoSkillPress(skill_id);
			break;
		case OperateType::OPT_SKILL_MOVE:
			skill_id = DataUtil::ReadInt32(req.Bytes, index, &index);
			move_p1 = DataUtil::ReadInt16(req.Bytes, index, &index);
			move_p2 = DataUtil::ReadInt16(req.Bytes, index, &index);
			player->DoSkillMove(skill_id, move_p1, move_p2);
			break;
		case OperateType::OPT_SKILL_RELEASE:
			skill_id = DataUtil::ReadInt32(req.Bytes, index, &index);
			move_p1 = DataUtil::ReadInt16(req.Bytes, index, &index);
			move_p2 = DataUtil::ReadInt16(req.Bytes, index, &index);
			player->DoSkillRelease(skill_id, move_p1, move_p2);
			break;
		default:
			break;
		}
	}

	void FightModule::OnFightResultRequest(NetDataItem* item)
	{
		int user_id = (int)item->key.second;
		CSFightResultRequest req;
		req.Unpack(item->data, 0);
		::printf("FightModule::OnFightResultRequest user_id:%d win_camp:%d\n", user_id, req.WinCamp);

		//必须是战斗中的玩家信息
		auto group = GetUserGroup(user_id);
		if (group == NULL)
		{
			return;
		}
		auto player = group->GetPlayer(user_id);
		if (player == NULL)
		{
			return;
		}
		player->SetWinCamp(req.WinCamp);
		if (group->GetState() == FightGroupState::FGS_FIGHTING)
		{
			//TODO:将操作数据提交战斗校验模块获取结果
			group->SetWinCamp(req.WinCamp);					//临时以第一个请求者为准
			group->SetState(FightGroupState::FGS_END);
		}
		CheckGroupEnd(group);
	}

	void FightModule::OnFightQuitRequest(NetDataItem* item)
	{
		int user_id = (int)item->key.second;
		CSFightQuitRequest req;
		req.Unpack(item->data, 0);
		::printf("FightModule::OnFightQuitRequest user_id:%d\n", user_id);

		auto group = GetUserGroup(user_id);
		if (group == NULL)
		{
			return;
		}
		auto player = group->GetPlayer(user_id);
		if (player == NULL)
		{
			return;
		}
		player->SetState(FightPlayerState::FPS_QUIT);

		//const Int32 SC_FIGHT_QUIT = 3408;					//退出回复
		SCFightQuitResponse res;
		SendNet(user_id, MsgID::SC_FIGHT_QUIT, &res);
		EventParam* ep = EventParam::Get(FightEvent::EID_FIGHT_OUT);
		ep->i1 = user_id;
		EventManager::GetInstance()->TriggerEvent(ep);
		CheckGroupClose(group);
	}

	void FightModule::OnFightFrameRecordRequest(NetDataItem* item)
	{
		int user_id = (int)item->key.second;
		CSFightFrameRecordRequest req;
		req.Unpack(item->data, 0);
		::printf("FightModule::OnFightFrameRecodRequest user_id:%d\n", user_id);

		auto group = GetUserGroup(user_id);
		if (group == NULL)
		{
			return;
		}

		//一次请求最多发送8次回复(128K的数据)
		int start = req.StartIndex;
		SCFightFrameRecordResponse res;
		for (int i = 0; i < 8; ++i)
		{
			if (start >= req.EndIndex)
			{
				break;
			}

			start = group->GetFrameRecord()->TakeRecord(start, req.EndIndex, i == 7, res);
			SendNet(user_id, MsgID::SC_FIGHT_FRAME_RECORD, &res);
		}
	}

	void FightModule::OnEventMatchComplete(int id, EventParam* ep)
	{
		//生成战斗组
		::printf("FightModule::OnEventMatchComplete users:%s\n", ep->s1.c_str());
		vector<int> user_ids;
		StringUtil::SplitToInt(ep->s1, "_", user_ids);
		FightGroupInfo* group = new FightGroupInfo(m_CurGroupID++);
		m_FightGroups.insert(make_pair(group->GetGroupID(), group));
		for (vector<int>::iterator itr = user_ids.begin(); itr != user_ids.end(); itr++)
		{
			int id = *itr;
			FightPlayerInfo* pinfo = new FightPlayerInfo(id);
			pinfo->SetRoleID((int)(itr - user_ids.begin() + 1));
			pinfo->SetState(FightPlayerState::FPS_NORMAL);
			m_UserToGroup.insert(make_pair(id, group->GetGroupID()));
			group->AddPlayerInfo(pinfo);
		}
		group->SetState(FightGroupState::FGS_SELECT_ROLE);
		group->SetStartTime(TimeUtil::GetCurrentMillisecond());

		//通知玩家战斗状态变化
		SCFightStateResponse res;
		LoginModule* login_module = GetServer()->GetModule<LoginModule>();
		FightPlayerInfoVector& players = group->GetPlayerInfos();
		res.State = (Byte)group->GetState();
		res.PlayerCount = (int)players.size();
		for (int i = 0; i < res.PlayerCount; ++i)
		{
			auto fp = players[i];
			Competition::Net::FightPlayerInfo nfp;

			nfp.UserID = fp->GetUserID();
			nfp.NickName = login_module->GetUser(fp->GetUserID())->GetNickName();
			nfp.RoleID = (SByte)fp->GetRoleID();
			nfp.RoleConfigID = 0;
			nfp.Confirm = 0;
			res.PlayerList.push_back(nfp);
		}
		res.Param = SelectRoleTime;
		for (FightPlayerInfoVector::iterator itr = players.begin(); itr != players.end(); itr++)
		{
			SendNet((*itr)->GetUserID(), MsgID::SC_FIGHT_STATE, &res);
		}
	}

	void FightModule::OnEventUserOutline(int id, EventParam* ep)
	{
		int user_id = ep->i1;
		::printf("FightModule::OnEventUserOutline user_id:%d\n", user_id);

		auto group = GetUserGroup(user_id);
		if (group == NULL)
		{
			return;
		}
		auto player = group->GetPlayer(user_id);
		if (player == NULL)
		{
			return;
		}
		if (player->GetState() == FightPlayerState::FPS_NORMAL)
		{
			player->SetState(FightPlayerState::FPS_OUTLINE);
		}
		
		EventParam* ep2 = EventParam::Get(FightEvent::EID_FIGHT_OUT);
		ep2->i1 = user_id;
		EventManager::GetInstance()->TriggerEvent(ep2);
		CheckGroupClose(group);
	}

	void FightModule::CheckGroupClose(FightGroupInfo* group)
	{
		//全部退出了则结束战斗
		FightPlayerInfoVector& players = group->GetPlayerInfos();
		bool all_quit = true;
		for (FightPlayerInfoVector::iterator itr = players.begin(); itr != players.end(); itr++)
		{
			int state = (*itr)->GetState();
			if (state == FightPlayerState::FPS_NORMAL)
			{
				all_quit = false;
				break;
			}
		}
		if (all_quit)
		{
			//移除战斗组
			for (FightPlayerInfoVector::iterator itr = players.begin(); itr != players.end(); itr++)
			{
				int uid = (*itr)->GetUserID();
				m_UserToGroup.erase(uid);
			}
			m_FightGroups.erase(group->GetGroupID());
			SAFE_DELETE(group);		//players不能再访问
		}
	}

	void FightModule::CheckGroupEnd(FightGroupInfo* group)
	{
		//判断仲裁结果是否出来
		if (group->GetWinCamp() == BelongCamp::None)
		{
			return;
		}

		//是否所有结果都收到了
		FightPlayerInfoVector& players = group->GetPlayerInfos();
		for (FightPlayerInfoVector::iterator itr = players.begin(); itr != players.end(); itr++)
		{
			if ((*itr)->GetWinCamp() == BelongCamp::None)
			{
				return;
			}
			if ((*itr)->GetWinCamp() != group->GetWinCamp())
			{
				//玩家计算结果与服务不一致
			}
		}

		//发送结果
		//const Int32 SC_FIGHT_RESULT = 3407;					//结果通知
		SCFightResultNotify ntf;
		ntf.WinCamp = group->GetWinCamp();
		for (FightPlayerInfoVector::iterator itr = players.begin(); itr != players.end(); itr++)
		{
			SendNet((*itr)->GetUserID(), MsgID::SC_FIGHT_RESULT, &ntf);
		}

		//移除战斗组
		for (FightPlayerInfoVector::iterator itr = players.begin(); itr != players.end(); itr++)
		{
			int uid = (*itr)->GetUserID();
			m_UserToGroup.erase(uid);
			EventParam* ep = EventParam::Get(FightEvent::EID_FIGHT_OUT);
			ep->i1 = uid;
			EventManager::GetInstance()->TriggerEvent(ep);
		}
		m_FightGroups.erase(group->GetGroupID());
		SAFE_DELETE(group);		//players不能再访问
	}
}
